package cn.biplam.common.tools;

import cn.biplam.common.wrapper.ErrorMessage;

/**
 * 	根据类名及详细参数动态创建类，根据方法名和方法参数执行类对应方法，任一被调用的类的构造函数参数或者方法参数如果为空返回异常。
 * @author XiaoRuxing
 * @create下午04:04:31
 * @version 1.0
 */
public class Call {

	private CallAction action;	

	/**按照参数类型自动匹配(default) */
	public static final char MODEL_AUTO_MATCH='0';
	/**不进行参数类型匹配，直接调用 */
	public static final char MODEL_NO_MATCH='1';
	/**按照传入的参数类名称进行匹配 */
	public static final char MODEL_MANUAL_MATCH='2';

	/**
	 * 	创建无构造函数类
	 * @param sClassName 类名
	 * @throws ErrorMessage 
	 */
	public Call(String sClassName) throws ErrorMessage{
		action=new CallAction(sClassName);
	}

	/**
	 * 根据传入类名、构造函数参数列表和参数值创建类，手动匹配模式
	 * @param sClassName     类名
	 * @param classParamTypes 参数类型列表
	 * @param classParams     参数值列表(可以传入多个参数值，顺序和个数与参数类型列表一致) 
	 * @throws ErrorMessage
	 */
	@SuppressWarnings("unchecked")
	public Call(String sClassName,Class[] classParamTypes,Object...classParams) throws ErrorMessage{
		this(MODEL_MANUAL_MATCH,sClassName,classParamTypes,classParams);
	}
	
	/**
	 * 根据传入类名、构造函数参数列表和参数值创建类，手动匹配模式
	 * @param sClassName     类名
	 * @param classParamTypes 参数类型列表
	 * @param classParams     参数值列表(可以传入多个参数值，顺序和个数与参数类型列表一致) 
	 * @throws ErrorMessage
	 */
	@SuppressWarnings("unchecked")
	public Call(char matchModel,String sClassName,Class[] classParamTypes,Object...classParams) throws ErrorMessage{
		/** 获取参数数组 */
		Object[] params=getParams(classParams);
		if(classParamTypes==null){
			classParamTypes = getParamTypes(params);
		}
		/** 如果参数列表中参数个数与参数类型列表中参数个数不一致抛出异常 */
		if(classParamTypes.length!=params.length){
			ErrorMessage eMg=new ErrorMessage("classParamTypes numbers can not match classParams");
			throw eMg;
		}
		try {
			/** 创建类实例 */
			action=new CallAction(matchModel,sClassName,classParamTypes,params);
		}catch (ErrorMessage e) {
			throw e;
		}catch (Exception e) {
			throw new ErrorMessage(e);
		}
	}


	/**
	 * 	按照默认的匹配模式创建类实例
	 * @param sClassName 类名
	 * @param classParam 构造方法参数(可传入多个参数)
	 * @throws ErrorMessage 如果构造方法参数为空返回空指针异常
	 */
	public Call(String sClassName,Object... classParams) throws ErrorMessage{
		this(MODEL_AUTO_MATCH,sClassName,classParams);
	}

	/**
	 * 按照指定匹配模式创建类实例
	 * @param matchModel 匹配模式(适用于自动匹配或者无匹配)
	 * @param sClassName  类名
	 * @param classParams 构造方法参数(可传入多个参数)
	 * @throws ErrorMessage
	 */
	@SuppressWarnings("unchecked")
	public Call(char matchModel,String sClassName,Object...classParams) throws ErrorMessage{
		this(matchModel,sClassName,null,classParams);
	}


	/**
	 * 根据方法名，执行类对应的无参方法
	 * @param sMethodName 方法名
	 * @return 方法执行结果
	 * @throws ErrorMessage 
	 */
	public Object run(String sMethodName) throws ErrorMessage{
		action.setMethod(sMethodName);
		return action.invoke();
	}

	/**
	 *  根据方法名，执行类对应的方法
	 * @param sMethodName 方法名
	 * @param methodParams 方法参数(可传入多个参数)
	 * @return 方法执行结果
	 * @throws ErrorMessage 如果方法参数为空返回空指针异常
	 */
	@SuppressWarnings("unchecked")
	public Object run(String sMethodName,Object... methodParams) throws ErrorMessage{
		Object obj;
		try{
			Object[] params=getParams(methodParams);
			Class[] paramTypes=getParamTypes(params);
			action.setMethod(sMethodName, paramTypes,params);
			obj=action.invoke();
		}catch(ErrorMessage e){
			throw e;
		}catch(Exception e){
			throw new ErrorMessage(e,"Call.run failed at "+this.getClassName());
		}
		return obj;
	}
	
	/**
	 * 返回反射类名称
	 * @return String
	 */
	public String getClassName(){
		return this.action.getClassName();
	}

	/**
	 * 获取传入实例的类型数组
	 * @param params 实例数组
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Class[] getParamTypes(Object[] params){
		if(params == null){
			return null;
		}
		Class[] paramTypes=new Class[params.length];
		for(int i=0;i<params.length;i++){
			paramTypes[i]=params[i].getClass();
		}
		return paramTypes;
	}

	/**
	 * 将传入的多个函数参数放入数组
	 * @param params 参数 可以是多个
	 * @return 参数数组
	 */
	private Object[] getParams(Object... params){
		return params;
	}

	/**
	 * 根据传入的多个类名称，获取多个类类型并放入数组
	 * @param classNames 类名称 可以是多个
	 * @return 类类型数组
	 * @throws ErrorMessage
	 */
	@SuppressWarnings("unchecked")
	public static final Class[] getClassTypeArray(String...classNames) throws ErrorMessage{
		
		if(classNames == null){
			return null;
		}
		/** 根据类名称获取类类型，依次保存到数组 */
		Class[] tempClass=new Class[classNames.length];
		try {
			for(int i=0;i<tempClass.length;i++){
				tempClass[i]=Class.forName(classNames[i]);
			}
		} catch (ClassNotFoundException e) {
			ErrorMessage eMg=new ErrorMessage(e);
			throw eMg;
		}
		return tempClass;
	}

	/**
	 * 将传入的多个类类型保存到类数组
	 * @param classes 类类型
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static final Class[] getClassTypeArray(Class<?>... classes){
		return classes;
	}

	/**
	 * 取得动态创建的类实例
	 * @return
	 */
	public Object getInstance(){
		return this.action.getMethodObject();
	}
}
